/*******************************************************************************
 *                                                                             *
 *  IrcMessage.cs                                                              *
 *                                                                             *
 *  IrcDotNet - Internet Relay Chat API for .NET and Mono                      *
 *  << http://code.google.com/p/ircdotnet >>                                   *
 *                                                                             *
 *  Copyright (C) 2006 Rodger Aiken (johnny.mn3m0nic@gmail.com)                *
 *                                                                             *
 *  IRC .NET is free software; you can redistribute it and/or modify it under  *
 *  the terms of the GNU Lesser General Public License as published by the     *
 *  Free Software Foundation; either version 2.1 of the License, or (at	your   *
 *  option) any later version.                                                 *
 *                                                                             *
 *  IRC .NET is distributed in the hope that it will be useful, but WITHOUT    *
 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or      *
 *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public        *
 *  License for more details.                                                  *
 *                                                                             *
 *  You should have received a copy of the GNU Lesser General Public License   *
 *  along with this library; if not, write to the Free Software Foundation,    *
 *  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA           *
 *                                                                             *
 *******************************************************************************/

using System;

namespace IrcDotNet {
	public sealed class IrcMessage {
		public sealed class MessagePrefix {
			private readonly string data;

			public string Data { get { return this.data; } }

			private readonly string serverName;

			public string ServerName { get { return this.serverName; } }

			private readonly string nickname;

			public string Nickname { get { return this.nickname; } }

			private readonly string userName;

			public string UserName { get { return this.userName; } }

			private readonly string hostName;

			public string HostName { get { return this.hostName; } }

			internal string Sender { get { return ( ( this.nickname == null ) ? this.serverName : this.nickname ); } }

			private MessagePrefix ( string data ) {
				this.data = ( ( data[0] == ':' ) ? data.Remove(0, 1).Trim() : data.Trim() );
				data = data.Trim();
				
				if ( !data.Contains("!") && !data.Contains("@") )
					this.serverName = data.Substring(0, data.Length);
				else {
					int u = data.IndexOf('!');
					int h = data.IndexOf('@');
					
					this.nickname = data.Substring(0, u);
					this.userName = data.Substring(( u + 1 ), ( h - u ));
					this.hostName = data.Substring(h, data.Length);
				}
			}

			internal static MessagePrefix Parse ( string prefix ) {
				if ( prefix == null )
					throw new ArgumentNullException("prefix");

				return new MessagePrefix(prefix);
			}
		}

		private readonly string data;

		public string Data { get { return this.data; } }

		private readonly MessagePrefix prefix;

		public MessagePrefix Prefix { get { return this.prefix; } }

		public string Sender { get { return this.prefix.Sender; } }

		private readonly string command;

		public string Command { get { return this.command; } }

		public int Numeric {
			get {
				int numeric = ( -1 );

				if ( Int32.TryParse(this.command, ref numeric) )
					return numeric;

				return -1;
			}
		}

		private readonly string[ ] parameters;

		public string[ ] Parameters { get { return this.parameters; } }

		public string Target {
			get {
				// If parameters is not null, and the first parameter is not a trailing parameter
				// then return it as the target.
				if ( ( this.parameters != null ) && ( this.parameters[0][0] != ':' ) )
					return this.parameters[0];

				return null;
			}
		}

		private IrcMessage ( string data ) {
			if ( ( data == null ) || ( data == "" ) )
				throw new ArgumentNullException("data");

			this.data = data;
			string[ ] fields = null;

			if ( data[0] == ':' )
				fields = data.Split(new char[ ] { ' ' }, 3, StringSplitOptions.RemoveEmptyEntries);
			else
				fields = data.Split(new char[ ] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries);

			// Process message prefix
			if ( ( fields != null ) && ( fields[0][0] == ':' ) )
				this.prefix = MessagePrefix.Parse(fields[0]);

			// String format of the message command
			this.command = fields[( fields[0][0] == ':' ) ? 1 : 0];

			if  ( ( ( fields[0][0] == ':' ) && ( fields.Length == 2 ) ) || ( ( fields[0][0] != ':' ) && ( fields.Length == 1 ) ) )
				this.parameters = new string[ ] { };
			else {
				// Split parameters into regular and trailing parts
				string[ ] tmp1 = fields[fields.Length - 1].Split(new string[ ] { " :" }, 2, StringSplitOptions.RemoveEmptyEntries);
				// Split regular parameters
				string[ ] tmp2 = tmp1[0].Split(new char[ ] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

				// If there were no trailing parameters shortcut, and assign
				// this.parameters to the array of regular parameters
				if ( tmp1.Length == 1 )
					this.parameters = ( ( string[ ] ) tmp2.Clone() );
				else if ( tmp1.Length == 2 ) {
					// If there were trailing parameters then, create an array of the
					// regular parameters and appened the trailing parameter to the end.
					string[ ] tmp3 = new string[tmp2.Length + 1];

					tmp2.CopyTo(tmp3, 0);

					tmp3[tmp2.Length] = ( ":" + tmp1[1] );
					this.parameters = ( ( string[ ] ) tmp3.Clone() );
				}
				else
					throw new FormatException("Unable to parse IRC protocol message correctly");
			}
		}

		public static IrcMessage Parse ( string message ) {
			if ( message == null )
				throw new ArgumentNullException("message");

			return new IrcMessage(message);
		}

		public override string ToString ( ) {
			return this.data;
		}
	}
}

